Rem  Copyright (c) 1999, 2000 by Marcelo F. Ochoa.  All Rights Reserved.
Rem
Rem   NAME
Rem     cache_bdy.pls - DBPrism / Cocoon2 External Cache Invalidator utilities
Rem   PURPOSE
Rem     Install the PL/SQL needed to run the XML Application.
Rem   NOTES
Rem
Rem   HISTORY
Rem     mochoa@ieee.org   02/17/02 -
Rem       changes according to syntax of DTD from ESI standard
Rem        http://www.w3.org/TR/esi-invp
Rem     mochoa@ieee.org   1/31/02 -  Creation version 1.0.0
Rem

CREATE OR REPLACE PACKAGE BODY cache AS

-- version 1.0.1
--   use ESI standard ESI invalidation protocol
--   use invalidator:invalidator as username/password
--   use uriprefix and uriexp argument instead of uri
-- version 1.0.0
-- initial

procedure cms_invalidate_page(machine in varchar2, 
                              port in integer, 
                              page_url in varchar2) is
  par cache_parameters;
begin
  par.num_vals := 2;
  par.names(1) := 'source';
  par.names(2) := 'printable';
  par.vals(1) := page_url;
  par.vals(2) := 'no';
  invalidate(machine,port,'/cms/','CMSj.header',par);
  invalidate(machine,port,'/cms/','CMSj.content',par);
end cms_invalidate_page;

procedure invalidate(machine in varchar2, 
                     port in integer, 
                     uriprefix in varchar2,
                     uriexp in varchar2,
                     sitemap in cache_parameters default null_parameter,
                     http in cache_parameters default null_parameter,
                     cookies in cache_parameters default null_parameter) is
  d integer;
  c  utl_tcp.connection;  -- TCP/IP connection to the Web server
  DQUOTE constant varchar2(1) :=  chr(34);
  CR constant varchar2(1) :=  chr(13);
  content_length integer;
  invalidate_msg varchar2(4000);

BEGIN
  -- Note: = Content-Length = 201 + 
  --                Length of uri to invalidate + 
  --                sitemap parameter + 
  --                http parameter +
  --                cookies                       
  content_length := LENGTH(uriprefix) + LENGTH(uriexp) + 201;
  -- adds sitemap parameters lines
  if sitemap.num_vals>0 then
    -- sums lines of type <OTHER TYPE="sitemap" NAME="xx" VALUE="yy"/>
    content_length := content_length + 48*sitemap.num_vals;
    for i in 1..sitemap.num_vals loop
      content_length := content_length + LENGTH(sitemap.names(i));
      content_length := content_length + LENGTH(sitemap.vals(i));
    end loop;
  end if;

  -- adds http parameters lines
  if http.num_vals>0 then
    -- sums lines of type <OTHER TYPE="http" NAME="xx" VALUE="yy"/>
    content_length := content_length + 45*http.num_vals;
    for i in 1..http.num_vals loop
      content_length := content_length + LENGTH(http.names(i));
      content_length := content_length + LENGTH(http.vals(i));
    end loop;
  end if;

  -- adds cookies parameters lines
  if cookies.num_vals>0 then
    -- sums lines of type <COOKIE NAME="xx" VALUE="yy"/>
    content_length := content_length + 34*cookies.num_vals;
    for i in 1..cookies.num_vals loop
      content_length := content_length + LENGTH(cookies.names(i));
      content_length := content_length + LENGTH(cookies.vals(i));
    end loop;
  end if;

  -- open connection
  c := utl_tcp.open_connection(machine, port); 

  -- Send the HTP Protocol Header
  -- send HTTP POST for DB Prism invalidator page
  -- requires an pipeline setting like this
  --   <map:match pattern="x-dbprism-cache-invalidate">
  --    <map:generate type="serverpages" src="invalidate.xsp"/>
  --    <map:serialize/>
  --   </map:match>

  d := utl_tcp.write_line(c, 'POST /dbprism/x-dbprism-cache-invalidate HTTP/1.0');  

  -- Note: The Authorization passes the User:Password as a base64 encoded
  --       string. ie. invalidator:invalidator =>  
  d := utl_tcp.write_line(c, 'Authorization: BASIC aW52YWxpZGF0b3I6aW52YWxpZGF0b3I=');  
  d := utl_tcp.write_line(c, 'Content-Length: ' || content_length);  

  -- send TWO CR's per HTTP Protocol  (Note: One from above and the other sent by write_line)
  -- (Note: If testing with telnet count cr as 2 characters)
  d := utl_tcp.write_line(c, '' );  

  -- send ESI Invalidation message 
  d := utl_tcp.write_line(c, '<?xml version=' || DQUOTE || '1.0' || DQUOTE || '?>');

  d := utl_tcp.write_line(c, '<INVALIDATION VERSION="WCS-1.0">');

  d := utl_tcp.write_line(c, '  <OBJECT>');

  d := utl_tcp.write_line(c, '    <ADVANCEDSELECTOR URIPREFIX=' 
                             || DQUOTE || uriprefix || DQUOTE ||
                             ' URIEXP=' 
                             || DQUOTE || uriexp || DQUOTE || '>');

  if sitemap.num_vals>0 then
    for i in 1..sitemap.num_vals loop
      d := utl_tcp.write_line(c, '      <OTHER TYPE="sitemap" NAME=' ||
                                                        DQUOTE || sitemap.names(i) ||
                                                        DQUOTE || ' VALUE=' ||
                                                        DQUOTE || sitemap.vals(i) ||
                                                        DQUOTE || '/>');
    end loop;
  end if;
  if http.num_vals>0 then
    for i in 1..http.num_vals loop
      d := utl_tcp.write_line(c, '      <OTHER TYPE="http" NAME=' ||
                                                     DQUOTE || http.names(i) ||
                                                     DQUOTE || ' VALUE=' ||
                                                     DQUOTE || http.vals(i) ||
                                                     DQUOTE || '/>');
    end loop;
  end if;
  if cookies.num_vals>0 then
    for i in 1..cookies.num_vals loop
      d := utl_tcp.write_line(c, '      <COOKIE NAME=' ||
                                              DQUOTE || cookies.names(i) ||
                                              DQUOTE || ' VALUE=' ||
                                              DQUOTE || cookies.vals(i) ||
                                              DQUOTE || '/>');
    end loop;
  end if;
  d := utl_tcp.write_line(c, '    </ADVANCEDSELECTOR>');
  d := utl_tcp.write_line(c, '    <ACTION REMOVALTTL=' || DQUOTE || '0' || DQUOTE || '/>');
  d := utl_tcp.write_line(c, '  </OBJECT>');
  d := utl_tcp.write_line(c, '</INVALIDATION>');
  utl_tcp.close_connection(c);
end invalidate;

BEGIN
  null_parameter.num_vals := 0;
END cache;
/
